use std::sync::Arc;

use super::hittable::*;

use crate::vec::*;
use crate::ray::Ray;
use super::material::Material;

pub struct Sphere {
    center: Point3,
    radius: f32,
    mat_ptr: Option<Arc<dyn Material>>,
}

impl Sphere {
    pub fn new(center: Point3, radius: f32, m: Arc<dyn Material>) -> Self {
        Self {center,radius, mat_ptr: Some(m)}
    }
}

impl Hittable for Sphere  {
    fn hit(&self, r: &Ray, t_min: f32, t_max:f32, rec: &mut HitRecord) -> bool {
        let oc = *r.origin() - self.center;
        let a = r.direction().length_squard();
        let half_b = oc.dot(r.direction());
        let c = oc.length_squard() - self.radius.powi(2);

        let discriminant = half_b.powi(2) - a * c;
        if discriminant < 0.0 {
            return false;
        }

        let sqrtd = discriminant.sqrt();
        
        // find the neraest root that lies in the acceptable range
        let mut root = (-half_b - sqrtd) /a;
        if root < t_min || root > t_max {
            root = (-half_b + sqrtd)/a;
            if root < t_min || root > t_max {
                return false;
            }
        }

        rec.set_t(root);
        rec.set_point(r.at(rec.t));

        let outwrad_normal = (rec.p - self.center) / self.radius;
        rec.set_face_normal(&r, &&outwrad_normal);

        match &self.mat_ptr {
            Some(v) => rec.mat_ptr = Some(v.clone()),
            None => rec.mat_ptr = None,
        }
        
        return true;
    }
}